package com.one.rope.mvp.basecore.util;

import com.one.rope.mvp.basecore.util.bean.CommonProxy;
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;
import java.lang.reflect.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Class工具类
 */
public class ClassUtils {

  /**
   * 动态初始化类
   *
   * @param cls 类
   * @param paramsValue 参数列表LinkedHashMap
   * @return T
   */
  @SuppressWarnings("unchecked")
  public static <T> T instance(Class<?> cls, LinkedHashMap<Class<?>, Object> paramsValue) {
    try {

      Class<?>[] clzParams = paramsValue.keySet().toArray(new Class<?>[]{});
      Object[] values = paramsValue.values().toArray(new Object[]{});
      Constructor<?> c = cls.getConstructor(clzParams);
      return (T) c.newInstance(values);
    } catch (Exception e) {
      return null;
    }
  }

  @SuppressWarnings("unchecked")
  public static <T> T instance(Class<?> cls) {
    try {
      Constructor<?> c = cls.getConstructor();
      return (T) c.newInstance();
    } catch (Exception e) {
      return null;
    }
  }

  /**
   * 动态初始化类,不带参数
   *
   * @param cls 类
   * @return T
   */
  @SuppressWarnings("unchecked")
  public static <T> T instanceGoogle(Class<?> cls) {
    try {
      Objenesis objenesis = new ObjenesisStd();
      return (T) objenesis.newInstance(cls);
    } catch (Exception e) {
      return null;
    }
  }

  /**
   * 获取当前类型所支持的泛型类的泛型类的实际类型
   */
  @SuppressWarnings("unchecked")
  public static <T> T getClassGenericFirst(Class<?> cls, int index) {
    return (T) ((ParameterizedType) cls.getGenericSuperclass()).getActualTypeArguments()[index];
  }

  /**
   * 获取当前类型所支持的泛型类的泛型类的实际类型
   */
  public static <T> T getClassGenericFirst(Class<?> cls) {
    return getClassGenericFirst(cls, 0);
  }

  /**
   * 代理执行方法
   *
   * @return Object
   */
  @SuppressWarnings("unchecked")
  public static <T> T proxy(T t, Class<?> proxyCls) {
    Class<?> cls = t.getClass();
    LinkedHashMap<Class<?>, Object> linkedHashMap = new LinkedHashMap<>(1);
    linkedHashMap.put(cls, t);
    Object proxyObject = instance(proxyCls, linkedHashMap);
    return (T) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),
        (InvocationHandler) proxyObject);
  }

  @SuppressWarnings("unchecked")
  public static <T> T proxy(CommonProxy<T> proxyObject) {
    T t = proxyObject.getT();
    Class<?> cls = t.getClass();
    LinkedHashMap<Class<?>, Object> linkedHashMap = new LinkedHashMap<>(1);
    linkedHashMap.put(cls, t);
    return (T) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),
        (InvocationHandler) proxyObject);
  }

  public static <T> T proxy(T object) {
    return proxy(new CommonProxy<T>(object));
  }


  public static Object findPropertyMethod(Object object, String[] properties, int index) {
    try {
      Class<?> cls = object.getClass();
      Method[] methods = cls.getMethods();
      String propertyName = "get" + properties[index];
      for (Method method : methods) {
        if (method.getName().replaceFirst("_", "").equalsIgnoreCase(propertyName)) {
          Object result = method.invoke(object);
          if ((index + 1) == properties.length) {
            return result;
          }
          if (result == null) {
            return null;
          }
          // Class<?> returnTypeCls = method.getReturnType();
          return findPropertyMethod(result, properties, index + 1);
        }
      }
    } catch (Exception e) {
      // TODO: handle handle
    }
    return null;
  }

  /**
   * 查询方法
   */
  public static Method findMethod(Class<?> cls, String propertyName) {
    try {
      Method[] methods = cls.getMethods();
      propertyName = "get" + propertyName;
      for (Method method : methods) {
        if (method.getName().replaceFirst("_", "").equalsIgnoreCase(propertyName)) {
          return method;
        }
      }
    } catch (Exception e) {
      // TODO: handle handle
    }
    return null;
  }

  /**
   * 执行访求
   *
   * @param object 类
   * @param propertyName 属性名
   */
  public static Object invokeMethod(Object object, String propertyName) {
    try {
      Class<?> cls = object.getClass();
      Method[] methods = cls.getMethods();
      propertyName = "get" + propertyName;
      for (Method method : methods) {
        if (method.getName().replaceFirst("_", "").equalsIgnoreCase(propertyName)) {
          Object result = method.invoke(object);
          return result;
        }
      }
    } catch (Exception e) {
      // TODO: handle handle
    }
    return null;
  }

  /**
   * 获取属性的值
   *
   * @param object 实例对象
   * @param propertyName 属性名称
   * @return Object 值
   */
  public static Object getPropertyValueDirect(Object object, String propertyName) throws Exception {
    Class<?> cls = object.getClass();
    Method method = cls.getMethod("get" + StringUtils.upperLeftOne(propertyName));
    propertyName = "get" + propertyName;
    return method.invoke(object);
  }

  /**
   * 动态设置属性值
   */
  public static void setPropertyValue(Object object, String propertyName, Object value) {
    try {
      Class<?> cls = object.getClass();
      Method[] methods = cls.getMethods();
      propertyName = "set" + propertyName;
      for (Method method : methods) {
        if (method.getName().replace("_", "").equalsIgnoreCase(propertyName)) {
          method.invoke(object, value);
          break;
        }
      }
    } catch (Exception e) {
    }
  }

  public static void setPropertyValueDirect(Object object, String propertyName, Object value)
      throws Exception {
    Class<?> cls = object.getClass();
    Method method = cls.getMethod("set" + StringUtils.upperLeftOne(propertyName), value.getClass());
    method.invoke(object, value);
  }

  public static void copyProperties(Object source, Object destination, boolean ignoreNull) {
    copyProperties(source, destination, ignoreNull, null, null);
  }

  public static void copyProperties(Object source, Object destination, String propertyName) {
    copyProperties(source, destination, new String[]{propertyName});
  }

  public static void copyProperties(Object source, Object destination, String[] includePropreties) {
    copyProperties(source, destination, false, includePropreties, null);
  }

  public static void copyProperties(Object source, Object destination) {
    copyProperties(source, destination, null, null);
  }

  public static void copyProperties(Object source, Object destination, String[] includePropreties,
      String[] excludeProerties) {
    copyProperties(source, destination, false, includePropreties, excludeProerties);
  }

  public static void copyProperties(Object source, Object destination, boolean ignoreNull,
      String[] includePropreties,
      String[] excludeProerties) {
    try {
      Class<?> cls = source.getClass();
      List<Method> methods = Arrays.asList(cls.getMethods()).stream()
          .filter((item) -> item.getName().startsWith("get")).collect(Collectors.toList());
      Class<?> desCls = destination.getClass();
      List<Method> desMethods = Arrays.asList(desCls.getMethods()).stream()
          .filter((item) -> item.getName().startsWith("set")).collect(Collectors.toList());
      Set<String> includeSet =
          includePropreties != null ? new HashSet<String>(Arrays.asList(includePropreties))
              : null;
      Set<String> excludeSet =
          excludeProerties != null ? new HashSet<String>(Arrays.asList(excludeProerties))
              : null;

      for (Method method : methods) {
        try {
          String propertyName = method.getName().replace("_", "");
          propertyName = propertyName.substring(3);
          if (includeSet != null) {
            if (!includeSet.contains(propertyName.toLowerCase())) {
              continue;
            }
          }
          if (excludeSet != null) {
            if (excludeSet.contains(propertyName.toLowerCase())) {
              continue;
            }
          }
          for (Method desMethod : desMethods) {
            String desPropertyName = desMethod.getName().replace("_", "");
            if (propertyName.equalsIgnoreCase(desPropertyName.substring(3))) {
              Object result = method.invoke(source);
              if (ignoreNull && result == null) {
                break;
              }
              desMethod.invoke(destination, result);
            }
          }
        } catch (Exception e) {
        }
      }
    } catch (Exception e) {
    }
  }


  /**
   * 是否为空属性
   */
  public static boolean isEmpty(Object object) {
    if (object == null) {
      return false;
    }
    List<Field> fields = FieldUtils.getFields(object.getClass());

    for (Field field : fields) {
      try {
        Object value = FieldUtils.getInstanceValue(object, field.getName());
        if (value != null) {
          return false;
        }
      } catch (Exception e) {
      }
    }
    return true;
  }

}
